
#include "IAlgorithm.h"
#include "member_BMesh.h"

using namespace BWE;

member_BMesh::member_BMesh(BMesh* mesh)
{
	boss = mesh;
	dirtyTree = true;
	dataPolicy = Policy_None;
}
member_BMesh::~member_BMesh()
{

}

void member_BMesh::freshFaceOctTree()
{
	BSpace treeSpace = faceOctTree->space();
	const BSpace& space = boss->space();
	if (treeSpace.contain(space))
		return;
	faceOctTree->reset(space);
	if (faces)
	{
		for (int i = 0; i < faces->size(); i++)
		{
			const BFace& face = (*faces)[i];
			const BVector& va = (*vertices)[face.a()];
			const BVector& vb = (*vertices)[face.b()];
			const BVector& vc = (*vertices)[face.c()];
			BSpace space = va;
			space.expand(vb);
			space.expand(vc);
			auto item = faceOctTree->create(space);
			FaceInfo& finfo = item->append();
			finfo.face = face;
			finfo.index = i;
		}
	}
	else
	{
		int faceIndex = 0;
		for (int i = 0; i < vertices->size(); i += 3)
		{
			BFace face(i, i + 1, i + 2);
			const BVector& va = (*vertices)[face.a()];
			const BVector& vb = (*vertices)[face.b()];
			const BVector& vc = (*vertices)[face.c()];
			BSpace space = va;
			space.expand(vb);
			space.expand(vc);
			auto item = faceOctTree->create(space);
			FaceInfo& finfo = item->append();
			finfo.face = face;
			finfo.index = faceIndex++;
		}
	}
}

void member_BMesh::buildTree(int startIndex, int endIndex)
{
	Node& node = treeNodes[lastIndex];
	int numIndices = endIndex - startIndex;
	if (numIndices == 1)
	{
		node = leafNodes[startIndex];
		lastIndex++;
		return;
	}

	BVector means;
	for (int i = startIndex; i < endIndex; i++)
	{
		means += leafNodes[i].center;
	}
	means /= numIndices;

	BVector variance;
	for (int i = startIndex; i < endIndex; i++)
	{
		BVector diff2 = leafNodes[i].center - means;
		variance += diff2 * diff2;
	}
	variance /= numIndices - 1;

	int splitIndex = startIndex;
	{
		int axis = MaxAxis(variance);
		BReal splitValue = means[axis];
		for (int i = startIndex; i < endIndex; i++)
		{
			const BVector& center = leafNodes[i].center;
			if (center[axis] > splitValue)
			{
				leafNodes.swap(i, splitIndex);
				splitIndex++;
			}
		}
		int numBalanced = numIndices / 3;
		if (splitIndex <= (startIndex + numBalanced) || splitIndex >= (endIndex - 1 - numBalanced))
		{
			splitIndex = startIndex + (numIndices >> 1);
		}
	}

	node.space.min() = localSpace.max();
	node.space.max() = localSpace.min();
	for (int i = startIndex; i < endIndex; i++)
	{
		const BSpace& space = leafNodes[i].space;
		node.space.expand(space);
	}

	int curIndex = lastIndex++;
	buildTree(startIndex, splitIndex);
	buildTree(splitIndex, endIndex);
	node.index = curIndex - lastIndex;
}
void member_BMesh::overlapping(ITriangleCallback* callback, const BSpace& space)
{
	if (dirtyTree)
	{
		if (faces)
		{
			for (int i = 0; i < faces->size(); i++)
			{
				const BFace& face = faces->at(i);
				BVector va = vertices->at(face.a());
				BVector vb = vertices->at(face.b());
				BVector vc = vertices->at(face.c());
				Node& node = leafNodes.append();
				node.space.reset(va);
				node.space.expand(vb);
				node.space.expand(vc);
				node.center = node.space.center();
				node.index = i;
			}
		}
		if (leafNodes.size())
		{
			lastIndex = 0;
			treeNodes.resize(2 * leafNodes.size());
			buildTree(0, leafNodes.size());
		}
		leafNodes.clear();
		dirtyTree = false;
	}
	int index = 0;
	while (index < lastIndex)
	{
		const Node& node = treeNodes[index];
		bool overlapped = space.intersect(node.space);
		if (overlapped && node.index >= 0)
		{
			processNode(callback, node.index);
		}
		if (overlapped || node.index >= 0)
		{
			index++;
		}
		else
		{
			index -= node.index;
		}
	}
}
void member_BMesh::overlapping(ITriangleCallback* callback, const BLine& line)
{
	int index = 0;
	while (index < lastIndex)
	{
		const Node& node = treeNodes[index];
		bool overlapped = line.intersect(node.space);
		if (overlapped && node.index >= 0)
		{
			processNode(callback, node.index);
		}
		if (overlapped || node.index >= 0)
		{
			index++;
		}
		else
		{
			index -= node.index;
		}
	}
}
void member_BMesh::processNode(ITriangleCallback* callback, int index)
{
	const BFace& face = faces->at(index);
	BTriangle triangle;
	triangle[0] = vertices->at(face.a());
	triangle[1] = vertices->at(face.b());
	triangle[2] = vertices->at(face.c());
	callback->process(triangle, index);
}
